/*******************************************************************************
* Copyright (c) 2009, 2012 EclipseSource and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* EclipseSource - initial API and implementation
******************************************************************************/
package org.eclipse.rap.ui.interactiondesign.layout;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.rap.rwt.SingletonUtil;
import org.eclipse.rap.ui.interactiondesign.layout.model.ILayoutSetInitializer;
import org.eclipse.rap.ui.interactiondesign.layout.model.Layout;
import org.eclipse.rap.ui.interactiondesign.layout.model.LayoutSet;
import org.eclipse.ui.internal.util.PrefUtil;
/**
* This class represents a singleton object of a registry for
* <code>{@link Layout}</code> objects. This will contain all <code>Layout
* </code>s, which are contributed to the
* <code>org.eclipse.rap.ui.layouts</code> extension point.
*
* @since 1.2
*/
public class LayoutRegistry {
/**
* This is the default <code>LayoutSet</code> id for the fallback mechanism.
*/
public static final String DEFAULT_LAYOUT_ID
= "org.eclipse.rap.ui.defaultlayout";
private static final String LAYOUT_EXT_ID
= "org.eclipse.rap.ui.layouts";
/**
* The key for saving key/value pairs of <code>LayoutSet</code>s.
*/
public static final String SAVED_LAYOUT_KEY = LAYOUT_EXT_ID + ".saved";
private static Map layoutMap;
private static Map layoutSetToPluginId;
private static List overridenLayoutSets;
static {
init();
}
private String activeLayoutId;
private Layout activeLayout;
private List builders;
private LayoutRegistry() {
activeLayoutId = DEFAULT_LAYOUT_ID;
builders = new ArrayList();
}
/**
* Returns the singleton instance of the <code>LayoutRegistry</code> object.
*
* @return the singleton instance.
*/
public static LayoutRegistry getInstance() {
return SingletonUtil.getSessionInstance( LayoutRegistry.class );
}
/**
* Saves the new <code>Layout</code> id in a
* <code>ScopedPreferenceStore</code>.
*
* @param id the new <code>Layout</code> id to save.
*/
public void saveLayoutId( final String id ) {
IPreferenceStore preferenceStore = PrefUtil.getAPIPreferenceStore();
preferenceStore.putValue( SAVED_LAYOUT_KEY, id );
preferenceStore.firePropertyChangeEvent( SAVED_LAYOUT_KEY, "", id );
}
/**
* Sets the active <code>Layout</code> to the one, which belongs to the
* id in the parameter and save the new id if necessary.
*
* @param id the new <code>Layout</code> id.
* @param save if <code>true</code> then the new <code>Layout</code> will be
* saved.
*/
public void setActiveLayout( final String id, final boolean save ) {
Object object = layoutMap.get( id );
Layout newActive = ( Layout ) object;
if( newActive != null ) {
activeLayoutId = id;
activeLayout = newActive;
if( save ) {
saveLayoutId( activeLayoutId );
}
}
}
/**
* This method will call the <code>{@link ElementBuilder#dispose()}</code>
* for all registered builders.
*
* @see ElementBuilder#dispose()
*/
public void disposeBuilders() {
for( int i = 0; i < builders.size(); i++ ) {
ElementBuilder builder = ( ElementBuilder ) builders.get( i );
builder.dispose();
}
}
/**
* Returns the active <code>Layout</code>.
*
* @return the active layout
* @see Layout
*/
public Layout getActiveLayout() {
Layout result = activeLayout;
if( result == null ) {
result = ( Layout ) layoutMap.get( activeLayoutId );
activeLayout = result;
}
return result;
}
/**
* Returns an <code>IExtension</code> array, which contains all Layouts
* contributed to the <code>org.eclipse.rap.ui.layouts</code>
* extension point.
*
* @return all <code>Layout</code>s as an <code>IExtension<code> array.
*/
public static IConfigurationElement[] getLayoutExtensions() {
IExtensionRegistry registry = Platform.getExtensionRegistry();
return registry.getConfigurationElementsFor( LAYOUT_EXT_ID );
}
/**
* Reads the saved <code>Layout</code> id from a <code>ScopedPreferenceStore
* </code>.
*
* @return the saved <code>Layout</code> id or
* <code>{@link IPreferenceStore#STRING_DEFAULT_DEFAULT}</code> if no id is
* saved.
*/
public String getSavedLayoutId() {
String result = IPreferenceStore.STRING_DEFAULT_DEFAULT;
IPreferenceStore preferenceStore = PrefUtil.getAPIPreferenceStore();
result = preferenceStore.getString( SAVED_LAYOUT_KEY );
return result;
}
/**
* This method is called, if the active <code>Layout</code> has changed. It
* will call <code>{@link ElementBuilder#dispose()}</code> for all registered
* builders.
*
* @see ElementBuilder#dispose()
*/
public void notifyLayoutChanged() {
disposeBuilders();
}
static String getPluginIdForLayoutSet( final String layoutSetId ) {
return ( String )layoutSetToPluginId.get( layoutSetId );
}
/**
* Adds a <code>{@link ElementBuilder}</code> to a List of builders.
*
* @param builder a instance of a <code>ElementBuilder</code>
*
* @see ElementBuilder
*/
void registerBuilder( final ElementBuilder builder ) {
builders.add( builder );
}
/**
* Initialize the <code>{@link LayoutSet}</code> contributed to the
* <code>org.eclipse.rap.ui.layouts</code> extension point.
*/
private static void init() {
layoutSetToPluginId = new HashMap();
layoutMap = new HashMap();
overridenLayoutSets = new ArrayList();
IConfigurationElement[] elements = getLayoutExtensions();
for( int i = 0; i < elements.length; i++ ) {
String id = elements[ i ].getAttribute( "id" );
Layout layout = ( Layout ) layoutMap.get( id );
IConfigurationElement[] layoutSets
= elements[ i ].getChildren( "layoutSet" );
if( layout == null ) {
layout = initLayout( layoutSets, id );
layoutMap.put( id, layout );
} else {
createLayoutSets( layoutSets, layout );
}
}
}
private static Layout initLayout( final IConfigurationElement[] elements,
final String id )
{
Layout result = new Layout( id );
createLayoutSets( elements, result );
return result;
}
private static void createLayoutSets(
final IConfigurationElement[] layoutSets,
final Layout layout )
{
if( layoutSets != null && layoutSets.length > 0 ) {
for( int i = 0; i < layoutSets.length; i++ ) {
IConfigurationElement layoutSetElement = layoutSets[ i ];
String pluginId = layoutSetElement.getContributor().getName();
String layoutSetId = layoutSetElement.getAttribute( "id" );
String overrides = layoutSetElement.getAttribute( "overridesId" );
if( overrides != null ) {
// clear the old layoutset if it exists and create it with the new
// content. Additional create a new layoutset with the new id if
// someone want to override it again.
layout.clearLayoutSet( overrides );
LayoutSet layoutSet = layout.getLayoutSet( overrides );
layoutSetToPluginId.remove( overrides );
layoutSetToPluginId.put( overrides, pluginId );
initializeLayoutSet( layoutSetElement, layoutSet );
LayoutSet overridingLayoutSet = layout.getLayoutSet( layoutSetId );
layoutSetToPluginId.put( layoutSetId, pluginId );
initializeLayoutSet( layoutSetElement, overridingLayoutSet );
overridenLayoutSets.add( overrides );
} else {
if( !overridenLayoutSets.contains( layoutSetId ) ) {
// a new layoutset will only created if it's not already overridden.
layout.clearLayoutSet( layoutSetId );
LayoutSet layoutSet = layout.getLayoutSet( layoutSetId );
layoutSetToPluginId.put( layoutSetId, pluginId );
initializeLayoutSet( layoutSetElement, layoutSet );
}
}
}
}
}
private static void initializeLayoutSet(
final IConfigurationElement layoutSetElement,
final LayoutSet layoutSet )
{
try {
Object initializer
= layoutSetElement.createExecutableExtension( "class" );
if( initializer instanceof ILayoutSetInitializer ) {
ILayoutSetInitializer layoutInitializer
= ( ILayoutSetInitializer ) initializer;
layoutInitializer.initializeLayoutSet( layoutSet );
}
} catch( CoreException e ) {
e.printStackTrace();
}
}
}